/*
 * Copyright 2011 android-jar-fixer authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.perunlabs.tool.fixandroidjar;

import static com.google.common.io.ByteStreams.toByteArray;
import static com.google.common.io.Closeables.closeQuietly;
import static com.perunlabs.tool.fixandroidjar.Transformer.transform;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import java.util.jar.JarOutputStream;


/**
 * Fixes the android.jar lib by removing 'throw new RuntimeException("Stub!")'
 * from all methods/constructors in all classes. Also removes package '/junit'
 * completely.
 */
public class FixAndroidJar {

  public static void fix(String inputFile, String outputFile) throws IOException {
    JarInputStream inputJar = new JarInputStream(new BufferedInputStream(new FileInputStream(
        inputFile)));
    JarOutputStream outputJar = new JarOutputStream(new BufferedOutputStream(new FileOutputStream(
        outputFile)));
    try {
      JarEntry inputEntry = inputJar.getNextJarEntry();
      while (inputEntry != null) {
        String name = inputEntry.getName();
        byte[] entryBytes = toByteArray(inputJar);
        if ((isClassFileOrDir(name)) && !isFromPackageToBeRemoved(name)) {
          JarEntry outputEntry = new JarEntry(name);
          outputEntry.setTime(inputEntry.getTime());
          outputJar.putNextEntry(outputEntry);
          if (isClassFile(name)) {
            outputJar.write(transform(entryBytes, false));
          } else {
            outputJar.write(entryBytes);
          }
          outputJar.closeEntry();
        }
        inputEntry = inputJar.getNextJarEntry();
      }
    } finally {
      closeQuietly(inputJar);
      closeQuietly(outputJar);
    }
    System.out.println("Finished: " + outputFile);
  }

  private static boolean isClassFileOrDir(String name) {
    return isClassFile(name) || name.endsWith("/");
  }

  private static boolean isClassFile(String name) {
    return name.endsWith(".class");
  }

  private static boolean isFromPackageToBeRemoved(String name) {
    return name.startsWith("junit/") || name.startsWith("java/");
  }
}
